Apache+mod_auth_openidc+mod_proxyでGrafanaをAuth0(OIDC)認証対応してみた
こんにちは。CX事業本部Delivery部のakkyです。
OSS版Grafanaでユーザー認証を行う方法には、組み込みのユーザーデータベースのほか、OAuth2やLDAPを使うことができます。 今回は、Apacheをリバースプロキシにしてmod_auth_openidcを使ってOIDC認証を行い、Grafanaへユーザー名とロールを渡す方法を検証しました。 IdPにはAuth0を使います。
mod_auth_openidcについては、以前にもブログが書かれていますのでご覧ください。
Auth0の設定
新たにアプリケーションを作り、mod_auth_openidcに設定するクライアントキーとクライアントシークレットを取得しておきます。
また、Grafanaのユーザーロールを指定するため、Auth0のuser_metadata.roleをトークンと一緒に返すように設定します。詳しくは以下の記事をご覧ください。
今回は、Actionsに置き換え、Login Flowに以下のようなスクリプトを設定しました。
exports.onExecutePostLogin = async (event, api) => { const namespace = 'https://myapp.example.com/'; api.idToken.setCustomClaim( `${namespace}user_metadata_role`, event.user.user_metadata.role ); return; };
ユーザーのuser_metadataにroleを追加しておきます。これがないとGrafanaでは閲覧専用のViewerになるようです。
{ "role": "Admin" }
Apacheを動かすコンテナの作成
Apacheにmod_auth_openidcをインストールしたコンテナを作ります。次にようなDockerfileを作ります。
FROM docker.io/httpd:bullseye COPY libapache2-mod-auth-openidc_2.4.13.2-1.bullseye_amd64.deb /root RUN apt update \ && apt install -y libcjose0 libhiredis0.14 apache2-api-20120211 apache2-bin \ && apt clean \ && rm -rf /var/lib/apt/lists/* RUN apt install -y /root/libapache2-mod-auth-openidc_2.4.13.2-1.bullseye_amd64.deb RUN cp /usr/lib/apache2/modules/mod_auth_openidc.so /usr/local/apache2/modules
ビルドする際には、mod_auth_openidcのGithub releaseからlibapache2-mod-auth-openidc_x.x.x.x-x.bullseye_amd64.debをダウンロードしておいてください。 バグや脆弱性の修正などがあるので、最新版を使ってください。
Apacheの設定(httpd.conf)
デフォルトのhttpd.confを元に、mod_proxy、mod_proxy_http、mod_proxy_wstunnel、mod_rewrite、mod_auth_openidcを有効にします。
LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_http.so LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so LoadModule rewrite_module modules/mod_rewrite.so LoadModule auth_openidc_module modules/mod_auth_openidc.so
mod_auth_openidcの設定は次のようにしました。
OIDCProviderMetadataURL https://xxxxxxxxxxxxxx.xx.auth0.com/.well-known/openid-configuration OIDCClientID XXXXXXXXXXXXXXXXXXXXXXXX OIDCClientSecret XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX OIDCProviderUserInfoEndpoint https://xxxxxxxxxxxxxx.xx.auth0.com/userinfo OIDCRedirectURI http://<コンテナのIPアドレス>:8080/secure/redirect_uri OIDCCryptoPassphrase <ランダムな文字列を設定する> OIDCScope "openid profile email" OIDCRemoteUserClaim email OIDCResponseType "code" OIDCStateMaxNumberOfCookies 5 true OIDCProviderEndSessionEndpoint https://xxxxxxxxxxxxxx.xx.auth0.com/oidc/logout
/secureの内部を認証することにして、/secure/grafanaをGrafanaにリバースプロキシすることにします。
<Location /secure> AuthType openid-connect Require valid-user </Location> <Proxy *> AuthType openid-connect Require valid-user RewriteEngine On RewriteRule .* - [E=PROXY_USER:%{LA-U:REMOTE_USER},NS] RequestHeader set X-WEBAUTH-USER "%{PROXY_USER}e" </Proxy> RequestHeader unset Authorization RewriteEngine on RewriteRule ^/secure/grafana$ /secure/grafana/ [R] ProxyRequests Off ProxyPreserveHost On ProxyPass /secure/grafana/api/live/ ws://localhost:3000/api/live/ ProxyPass /secure/grafana/ http://localhost:3000/
Grafanaの脆弱性対策のため、ProxyPreserveHost OnとしてHostヘッダを付けないとうまく動きませんでした。 https://grafana.com/blog/2022/02/08/grafana-7.5.15-and-8.3.5-released-with-moderate-severity-security-fixes/
Grafanaの設定
Grafana側は、ヘッダで渡された内容を認証情報として使用するように設定します。
上から3行がリバースプロキシを使うための設定で、残りが認証情報プロキシの設定です。
GF_AUTH_PROXY_HEADER_NAMEで認証情報として使うヘッダ名を指定します。 また、GF_AUTH_PROXY_HEADER_NAMEでロールなどの補足情報に使うヘッダ名を指定しています。
Grafanaをコンテナで動かすときには、設定をenv_fileで行うと便利です。次のように設定しました。
GF_SERVER_DOMAIN=<GrafanaのドメインまたはIPアドレス> GF_SERVER_ROOT_URL=%(protocol)s://%(domain)s:%(http_port)s/secure/grafana/ GF_SERVER_SERVE_FROM_SUB_PATH=true GF_AUTH_PROXY_ENABLED=true GF_AUTH_PROXY_HEADER_NAME=OIDC_CLAIM_email GF_AUTH_PROXY_HEADER_PROPERTY=email GF_AUTH_PROXY_AUTO_SIGN_UP=true GF_AUTH_PROXY_SYNC_TTL=60 GF_AUTH_PROXY_WHITELIST= GF_AUTH_PROXY_HEADERS=Role:OIDC_CLAIM_https---myapp.example.com-user_metadata_role GF_AUTH_PROXY_ENABLE_LOGIN_TOKEN=false GF_AUTH_DISABLE_LOGIN_FORM=true GF_AUTH_SIGNOUT_REDIRECT_URL=http://<GrafanaのドメインまたはIPアドレス>/secure/redirect_uri?logout=<ログアウト後のリダイレクト先をURLエンコードしたアドレス>
今回は実験として手元で動かしているのでユーザー認証をする場所もhttpを使っていますが、実運用時にはhttpsで保護してください。
動作確認
以上の設定でApacheのコンテナとGrafanaのコンテナを動かし、ログインとログアウトがきちんとできることを確認できました。 設定を間違えると、ログインできるのにログアウトできなくなったりします。
GrafanaできちんとRoleが設定されていることも確認できました。
また、ログインには脆弱性が紛れ込みやすいので、運用時には十分検証を行ってください。